package com.xcity.db.entity;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSONObject;
import com.xcity.db.mapper.PlayerMapper;
import com.xcity.game.achievement.AchievementManager;
import com.xcity.game.activity.newplayer.NewPlayerTask;
import com.xcity.game.activity.newplayer.NewPlayerTaskManager;
import com.xcity.game.adventure.model.Adventure;
import com.xcity.game.assist.AssistManager;
import com.xcity.game.battle.pve.PVEManager;
import com.xcity.game.battle.res.ResStageManager;
import com.xcity.game.buff.BuffManager;
import com.xcity.game.buildv2.BuildManagerV2;
import com.xcity.game.combat.CombatUtils;
import com.xcity.game.combat.attr.CombatAttribute;
import com.xcity.game.combat.attr.CombatAttributeType;
import com.xcity.game.combat.attr.response.CombatAttributeInfo;
import com.xcity.game.combat.calc.CombatAttributeCalculator;
import com.xcity.game.combat.calc.impl.PlayerCombatAttributeCalculator;
import com.xcity.game.combat.unit.CombatableBase;
import com.xcity.game.common.Cause;
import com.xcity.game.common.ConfirmOperation;
import com.xcity.game.common.Currency;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.LogCause;
import com.xcity.game.common.PlayerPool;
import com.xcity.game.conquests.Conquests;
import com.xcity.game.employee.EmployeeManager;
import com.xcity.game.employee.template.EmployeeQualityUpTemplate;
import com.xcity.game.equip.Equipments;
import com.xcity.game.event.GameEvents;
import com.xcity.game.financial.FinancialManager;
import com.xcity.game.formation.FormationManager;
import com.xcity.game.io.SerializeStream;
import com.xcity.game.io.Serializer;
import com.xcity.game.io.SerializerUtils;
import com.xcity.game.item.Bag;
import com.xcity.game.map.MineReportManager;
import com.xcity.game.map.Mines;
import com.xcity.game.peakroad.model.PeakRoadInstance;
import com.xcity.game.pet.PetManager;
import com.xcity.game.player.PlayerUtils;
import com.xcity.game.player.template.DestinyTemplate;
import com.xcity.game.skill.SkillUtils;
import com.xcity.game.skill.v2.DefaultSkillV2;
import com.xcity.game.skill.v2.SkillManagerV2;
import com.xcity.game.task.TaskManager;
import com.xcity.game.vip.VipTemplate;
import com.xcity.game.vip.VipUtils;
import com.xcity.pomelo.push.SyncPush;
import com.xcity.pomelo.push.msg.StoneLackPush;
import com.xcity.pomelo.push.sync.IntSync;
import com.xcity.pomelo.push.sync.LongSync;
import com.xcity.pomelo.push.sync.MapSync;
import com.xcity.util.DBUtils;
import com.xcity.util.ExpCalc2;
import com.xcity.util.IdUtils;

import naga.x.App;
import naga.x.common.Initializable;
import naga.x.common.Updatable;
import naga.x.db.type.PropertyPool;
import naga.x.game.GameUnit;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Client;
import naga.x.net.Packet;
import naga.x.net.Session;
import naga.x.net.impl.pomelo.packet.KickPacket;
import naga.x.util.SessionUtils;

public class Player extends AbstractPlayer implements Client, Initializable, Updatable, GameUnit, CombatableBase/*, EnhancedUnit*/, Serializer {

	protected Bag bag;
	
//	protected int expOfNowLvl;
//	protected int nextLvlNeedExp;
	@Deprecated
	protected int maxBuildNum; // 当前等级可建造的最大建筑数量
	@Deprecated
	protected int maxBuildNumOfNextGrade; // 下一个档次最大建筑数量
	@Deprecated
	protected int nextMaxBuildNumNeedLvl; // 下一个最大建筑数量档次所需等级
	@Deprecated
	protected int risk; // 风险值
//	protected int attack; // 攻击力
//	protected int hp; // 血量,pve中用到
	
	protected Session session;
	protected User account;
	
	protected State state = State.LOADED;
	public static enum State {
		LOADED, INITED
	}
	
	public static final String DEFAULT_ICON = "resource/assets/dynamic/head/1.png"; // 男
	public static final String DEFAULT_FEMALE_ICON = "resource/assets/dynamic/head/2.png"; // 女
	
	protected ConfirmOperation op; // 当前需确认的操作
	
	public static final int STRENGTH_RECOVERY_VALUE = 1; // 每5分钟恢复1点体力
	public static final int STRENGTH_RECOVERY_TIME_INTERVAL = 5 * 60 * 1000; // 自动恢复体力时间间隔(5分钟)
	public static int STRENGTH_RESTORE_VALUE; //每次购买(恢复)体力
	public static final int VIGOUR_RECOVER_MAX_VALUE = 100;
	public static int VIGOUR_RECOVER_VALUE;
	public static int VIGOUR_RECOVER_TIME_INTERVAL;
	public static int VIGOUR_RESTORE_VALUE;
	public static int MONEY_RESTORE_VALUE;
	protected int strength/*免费体力*/, strength2/*花钱购买的体力*/;
	protected long lastUpdateStrTime; // 上一次恢复体力的时间
	protected long lastSyncOnlineTime;
	protected int circleScore;//当前欢乐转盘积分
	protected int circleFreeCount;//免费欢乐转盘剩余次数
	
	protected NewPlayerTaskManager newPlayerTask;//新角色活动任务 学名:开服狂欢
	
	protected int vigour;//精力
	protected long lastUpdateVigourTime;//上一次恢复精力
	
	protected int bond;//债券 30天签到中的豪华签到产出的代币
	
	protected Map<Integer, Integer> suitMap;
	
	protected int combatPower; // 战斗力
	protected long lastUpdateSkillPointsTime;
//	@Deprecated
//	protected Map<Integer, List<Long>> mineMap;//mineid2eids
	protected CombatAttributeCalculator<Player> calc = new PlayerCombatAttributeCalculator(this);

	public Player() {}
	
	public Player(long userId, String name, String icon, byte sex) {
		this.id = IdUtils.nextPlayerId();
		this.userId = userId;
		this.name = name;
		this.sex = sex == MALE ? MALE : FEMALE;
		this.icon = PlayerUtils.mappingIcon(null, icon, this.sex);
		this.level = 1;
		this.createTime = new Date();
		this.lastLoginTime = new Date();
		this.pool = new PropertyPool();
		this.strength = PlayerUtils.getMaxStrength(this);
		this.circleScore = 0;
		this.circleFreeCount = 0;
		this.vigour = VIGOUR_RECOVER_MAX_VALUE;
		suitMap = new ConcurrentHashMap<Integer, Integer>(32);
		pool.put(PlayerPool.PROPERTY_STRENGTH, strength);
//		// 新建角色避免世界事件不必要的检测
//		pool.put(PlayerPool.PROPERTY_LAST_WORLD_EVENT_END_TIME, TimeUpdater.getInstance().now());
		pool.put(PlayerPool.PROPERTY_LAST_RESET_STRENGTH_DAY, TimeUpdater.getInstance().today());
		pool.put(PlayerPool.PROPERTY_VIGOUR, this.vigour);
		pool.put(PlayerPool.PROPERTY_SKILL_POINTS, GameStaticConfig.maxSkillPoints);
	}

	@Override
	public Session getSession() {
		return session;
	}

	@Override
	public void setSession(Session session) {
		Session sess;
		if ((sess = this.session) != null && sess != session && sess.isConnected()) {
			sess.setAttribute(SessionUtils.KICKED, true);
			sess.send(KickPacket.INSTANCE);
			sess.close(true);
		}
		this.session = session;
	}
	
	public User getAccount() {
		return account;
	}
	
	public void setAccount(User account) {
		this.account = account;
	}

//	public int getExpOfNowLvl() {
//		return expOfNowLvl;
//	}
//
//	public void setExpOfNowLvl(int expOfNowLvl) {
//		this.expOfNowLvl = expOfNowLvl;
//	}
//
//	public int getNextLvlNeedExp() {
//		return nextLvlNeedExp;
//	}
//
//	public void setNextLvlNeedExp(int nextLvlNeedExp) {
//		this.nextLvlNeedExp = nextLvlNeedExp;
//	}

	@Deprecated
	public int getMaxBuildNum() {
		return maxBuildNum;
	}

	@Deprecated
	public int getMaxBuildNumOfNextGrade() {
		return maxBuildNumOfNextGrade;
	}

	@Deprecated
	public int getNextMaxBuildNumNeedLvl() {
		return nextMaxBuildNumNeedLvl;
	}

	@Deprecated
	public int getRisk() {
		return risk;
	}
	
	public void setRisk(int risk) {
		this.risk = risk;
	}

	public void fireFixedAssetsChanged() {
		long newVal = PlayerUtils.calcFixedAssets(this);
		if (newVal != fixedAssets) {
			fixedAssets = newVal;
			send(new LongSync(SyncPush.SYNC_FIXED_ASSETS, newVal));
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_FIX_ASSETS_CHANGED, this);
		}
	}
	
	public boolean add(Currency currency, int num, String cause) {
		switch (currency) {
			case GOLD:
				return addGold(num, cause);
			case STONE:
				return addStone(num, cause);
			case STRENGTH:
				return addStrength(num, cause);
			case HONOR:
				return addHonor(num, cause);
			case JOY_BEANS:
				return addJoyBeans(num, cause);
			default:
				return false;
		}
	}
	
	public boolean cost(Currency currency, long num, String cause) {
		switch (currency) {
			case GOLD:
				return costGold(num, cause);
			case STONE:
				return costStone((int) num, cause);
			case STRENGTH:
				return decStrength((int) num, cause);
			case HONOR:
				return decHonor((int) num, cause);
			case JOY_BEANS:
				return decJoyBeans((int) num, cause);
			case GUILD_SCORE:
				return decGuildScore((int) num, cause);
			default:
				return false;
		}
	}
	
	@SuppressWarnings("incomplete-switch")
	public boolean isEnough(Currency currency, int num) {
		if (num <= 0) {
			return false;
		}
		switch (currency) {
			case GOLD:
				return isGoldEnough(num);
			case STONE:
				return isStoneEnough(num);
//			case RECHARGE_STONE:
//				return false;
			case STRENGTH:
				return getStrength() >= num;
			case HONOR:
				return pool.getIntValue(PlayerPool.PROPERTY_HONOR) >= num;
			default:
				return false;
		}
	}

//	@Deprecated
	public boolean addGold(long gold, String cause) {
		if (gold <= 0 || this.gold + gold <= 0) {
			return false;
		}
		long oldVal = this.gold;
		this.gold += gold;
		if (state == State.INITED) {
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_GOLD_CHANGED, this, gold, cause);
			send(new LongSync(SyncPush.SYNC_GOLD, this.gold));
		}
		LOG.info("[ADDGOLD]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.gold, cause);
		return true;
	}
	
	public boolean addGold(long gold, LogCause cause) {
		if (gold <= 0 || this.gold + gold <= 0) {
			return false;
		}
		long oldVal = this.gold;
		this.gold += gold;
		if (state == State.INITED) {
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_GOLD_CHANGED, this, gold, cause);
			send(new LongSync(SyncPush.SYNC_GOLD, this.gold, cause));
		}
		LOG.info("[ADDGOLD]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.gold, cause);
		return true;
	}
	
	public boolean addStone(int stone, String cause) {
		if (stone <= 0 || this.stone + stone <= 0) {
			return false;
		}
		int oldVal = this.stone;
		this.stone += stone;
		if (state == State.INITED) {
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_STONE_CHANGED, this, stone);
			send(new IntSync(SyncPush.SYNC_STONE, this.stone));
		}
		LOG.info("[ADDSTONE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.stone, cause);
		return true;
	}
	
	public boolean costGold(long gold, String cause) {
		if (gold <= 0 || this.gold < gold) {
			return false;
		}
		long oldVal = this.gold;
		this.gold -= gold;
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_GOLD_CHANGED, this, -gold, cause);
		send(new LongSync(SyncPush.SYNC_GOLD, this.gold));
		LOG.info("[DECGOLD]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.gold, cause);
		return true;
	}
	
	public boolean costStone(int stone, String cause) {
		if (stone <= 0 || this.stone < stone) {
			send(StoneLackPush.DEFAULT);
			return false;
		}
		int oldVal = this.stone;
		this.stone -= stone;
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_STONE_CHANGED, this, -stone);
		send(new IntSync(SyncPush.SYNC_STONE, this.stone));
		LOG.info("[DECSTONE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.stone, cause);
		return true;
	}
	
	public boolean isGoldEnough(long num) {
		return gold >= num;
	}
	
	public boolean isStoneEnough(int num) {
		boolean lack = stone < num;
		if (lack) {
			send(StoneLackPush.DEFAULT);
		}
		return !lack;
	}
	
	public boolean addExp(int val, String cause) {
		ExpCalc2 calc = PlayerUtils.getExpCalc();
		if (val <= 0 || this.level >= calc.getMaxLevel()) {
			return false;
		}
		long oldExp = this.exp;
		this.exp += val;
//		this.expOfNowLvl += val;
		int oldLevel = this.level;
//		setLevel(PlayerUtils.exp2Lvl(exp));
		int[] result = calc.calc(oldLevel, (int) this.exp);
		this.level = result[0];
		this.exp = result[1];
		if (this.level > oldLevel) {
//			setExpOfNowLvl(PlayerUtils.getExpOfNowLvl(exp));
//			setNextLvlNeedExp(PlayerUtils.getNextLvlNeedExp(getLevel()));
//			maxBuildNum = PlayerUtils.getMaxBuildNum(level);
//			maxBuildNumOfNextGrade = PlayerUtils.getMaxBuildNumOfNextGrade(maxBuildNum);
//			nextMaxBuildNumNeedLvl = PlayerUtils.getMaxBuildNumNeedLvl(maxBuildNumOfNextGrade);
			int maxStr = PlayerUtils.getMaxStrength(this);
//			int str = maxStr - getStrength();
			int strGift = PlayerUtils.getTemplate(this).getStrGift();
//			if (str > strGift) {
//				str = strGift;
//			}
			addStrength(strGift, Cause.LEVEL_UP); // 恢复体力（最多25点）
			
			int vigourGift = PlayerUtils.getTemplate(this).getVigourGift();
			addVigour(vigourGift, Cause.LEVEL_UP);// 恢复精力（最多5点.....）
			
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_PLAYER_LEVEL_UP, this, oldLevel);
//			send(new LevelUpPush(this));
			send(new IntSync(SyncPush.SYNC_LEVEL, this.level));
			send(new IntSync(SyncPush.SYNC_EXP_MAX, calc.getExp(this.level + 1)));
//			send(new IntSync(SyncPush.SYNC_BUILD_BLOCK, this.maxBuildNum));
//			send(new IntSync(SyncPush.SYNC_NEXT_GRADE_BUILD_BLOCK, this.maxBuildNumOfNextGrade));
//			send(new IntSync(SyncPush.SYNC_NEXT_GRADE_BUILD_BLOCK_NEED_LEVEL, this.nextMaxBuildNumNeedLvl));
//			send(new CustomSync(SyncPush.SYNC_ATTR, new PlayerAttribute(this)));
			send(new IntSync(SyncPush.SYNC_MAX_STRENGTH, maxStr));
			fireAttributesChanged(CombatAttributeType.MASK_FULL);
		}
//		send(new ExpAddedPush(this, val, cause));
		send(new IntSync(SyncPush.SYNC_EXP, (int) this.exp));
		LOG.info("[ADDEXP]ID[{}]OLD[{}]NEW[{}]LVL[{}]VAL[{}]CAUSE[{}]", id, oldExp, exp, level, val, cause);
		return true;
	}
	
	public Bag getBag() {
		return bag;
	}

	@Override
	public void init() {
		// init manager
//		if (buildings == null)
//			buildings = new BuildManager(this, null);
		if (buffs == null)
			buffs = new BuffManager(this, null);
		if (tasks == null)
			tasks = new TaskManager(this);
		if (achievements == null)
			achievements = new AchievementManager(this, null);
		if (financials == null)
			financials = new FinancialManager(this, null);
		if (pets == null)
			pets = new PetManager(this, null);
		if (employees == null)
			employees = new EmployeeManager(this, null);
		if (pveStages == null)
			pveStages = new PVEManager(this, null, null);
		if (equips == null)
			equips = new Equipments(this, null);
		if (conquests == null)
			conquests = new Conquests(this, null);
		if (skillManager == null)
			skillManager = new SkillManagerV2(this, SkillUtils.createActiveSkill(this), SkillUtils.createPassiveSkills(this));
		if (adventure == null)
			adventure = new Adventure(this);
		if (buildings2 == null)
			buildings2 = new BuildManagerV2(this, null, 0, null);
		if (peakRoadInstance == null)
			peakRoadInstance = new PeakRoadInstance(this);
		if (resStages == null){
			resStages = new ResStageManager(this, null, null);
		}
		if (formations == null)
			formations = new FormationManager(this, null);
		if (mineReports == null){
			mineReports = new MineReportManager(this, null);
		}
		if (assists == null){
			assists = new AssistManager(this, null);
		}
		if( mines == null){
			mines = new Mines(this, null);
		}
		// init bag
		bag = new Bag(this);
		// init base property
//		setLevel(PlayerUtils.exp2Lvl(exp));
//		setExpOfNowLvl(PlayerUtils.getExpOfNowLvl(exp));
//		setNextLvlNeedExp(PlayerUtils.getNextLvlNeedExp(getLevel()));
		maxBuildNum = PlayerUtils.getMaxBuildNum(level);
		maxBuildNumOfNextGrade = PlayerUtils.getMaxBuildNumOfNextGrade(maxBuildNum);
		nextMaxBuildNumNeedLvl = PlayerUtils.getMaxBuildNumNeedLvl(maxBuildNumOfNextGrade);
//		risk = PlayerUtils.calcRisk(buildings.getBuildings());
//		fixedAssets = PlayerUtils.calcFixedAssets(id, buildings.getBuildings());
//		fixedAssets = PlayerUtils.calcFixedAssets(this);
		strength = pool.getIntValue(PlayerPool.PROPERTY_STRENGTH);
		strength2 = pool.getIntValue(PlayerPool.PROPERTY_STRENGTH2);
		circleFreeCount = pool.getIntValue(PlayerPool.PROPERTY_CIRCLE_FREE_COUNT);
		circleScore = pool.getIntValue(PlayerPool.PROPERTY_CIRCLE_SCORE);
		lastUpdateStrTime = pool.getLongValue(PlayerPool.PROPERTY_LAST_UPDATE_STRENGTH_TIME);
		vigour = pool.getIntValue(PlayerPool.PROPERTY_VIGOUR);
		lastUpdateVigourTime = pool.getLongValue(PlayerPool.PROPERTY_LAST_UPDATE_VIGOUR_TIME);
		lastUpdateSkillPointsTime = pool.getLongValue(PlayerPool.PROPERTY_LAST_UPDATE_SKILL_POINTS_TIME);
		bond = pool.getInt(PlayerPool.PROPERTY_THIRTY_DAY_BOND, 0);
		if (lastUpdateStrTime == 0L) {
			lastUpdateStrTime = lastLogoutTime != null ? lastLogoutTime.getTime() : TimeUpdater.getInstance().now();
		}
		if (lastUpdateVigourTime == 0L) {
			lastUpdateVigourTime = lastLogoutTime != null ? lastLogoutTime.getTime() : TimeUpdater.getInstance().now();
		}
		if (lastUpdateSkillPointsTime == 0L) {
			lastUpdateSkillPointsTime = lastLogoutTime != null ? lastLogoutTime.getTime() : TimeUpdater.getInstance().now();
		}
		JSONObject map = pool.getJSONObject(PlayerPool.PROPERTY_SUIT_MAP);
		if (map == null) {
			map = new JSONObject();
		}
		if (suitMap == null) {
			suitMap = new ConcurrentHashMap<Integer, Integer>(32);
		}
		for (String idStr : map.keySet()) {
			int val = map.getIntValue(idStr);
			if (val > 0) {
				suitMap.put(Integer.parseInt(idStr), val);
			}
		}
		if (newPlayerTask == null) {
			newPlayerTask = new NewPlayerTaskManager(this, null);
		}
		calc.calc();
		combatPower = CombatUtils.calcCombatPower(this);
		
//		JSONObject _map = pool.getJSONObject(PlayerPool.PROPERTY_TAKE_MINE_MAP);
//		if(_map == null){
//			_map = new JSONObject();
//		}
//		if(mineMap == null){
//			mineMap = new ConcurrentHashMap<Integer, List<Long>>(8);
//		}
//		try {
//			for (String idStr : _map.keySet()) {
////			int val = _map.getIntValue(idStr);
//				String val = _map.getString(idStr);
//				List<Long> arr = JSON.parseArray(val, Long.class);
////				JSONArray jsonArray = _map.getJSONArray(idStr);
////				int size = jsonArray.size();
////				List<Long> arr = new ArrayList<Long>();
////				for(int i = 0; i < size; i++){
////					arr.add(jsonArray.getLongValue(i));
////				}
//				mineMap.put(Integer.parseInt(idStr), arr);
//			}
//		} catch (Exception e) {
//			mineMap.clear();
//		}
		
		state = State.INITED;
	}
	
	public void save() {
		// 同步内存数据
		doSyncPool();
		
		DBUtils.update(this, PlayerMapper.class);
		bag.save();
		employees.save();
	}
	
	public void doSyncPool() {
		pool.put(PlayerPool.PROPERTY_STRENGTH, strength);
		pool.put(PlayerPool.PROPERTY_STRENGTH2, strength2);
		pool.put(PlayerPool.PROPERTY_LAST_UPDATE_STRENGTH_TIME, lastUpdateStrTime);
		pool.put(PlayerPool.PROPERTY_CIRCLE_SCORE, circleScore);
		pool.put(PlayerPool.PROPERTY_CIRCLE_FREE_COUNT, circleFreeCount);
		pool.put(PlayerPool.PROPERTY_VIGOUR, vigour);
		pool.put(PlayerPool.PROPERTY_LAST_UPDATE_VIGOUR_TIME, lastUpdateVigourTime);
		pool.put(PlayerPool.PROPERTY_THIRTY_DAY_BOND, bond);
		pool.put(PlayerPool.PROPERTY_LAST_UPDATE_SKILL_POINTS_TIME, lastUpdateSkillPointsTime);
		
		JSONObject map = new JSONObject();
		for(Integer key : suitMap.keySet()){
			int val = suitMap.get(key);
			if(val > 0){
				map.put(String.valueOf(key), val);
			}
		}
		pool.put(PlayerPool.PROPERTY_SUIT_MAP, map);
		
//		JSONObject _map = new JSONObject();
//		for(Integer key : mineMap.keySet()){
//			List<Long> eids = mineMap.get(key);
//			_map.put(String.valueOf(key), JSON.toJSONString(eids));
//		}
//		pool.put(PlayerPool.PROPERTY_TAKE_MINE_MAP, _map);
		
		List<NewPlayerTask> taskList = newPlayerTask.getTasks();
		for (int i = 0;i < taskList.size(); i++){
			NewPlayerTask task = taskList.get(i);
			int poolVal = task.calcPoolVal();
			pool.put(MessageFormat.format(NewPlayerTaskManager.STR_POOL_PREFIX, task.getTemplate().getId()), poolVal);
		}
	}

	@Override
	public boolean update() {
//		buildings.update();
		buildings2.update();
		conquests.update();
		assists.update();
		buffs.update();
		pets.update();
//		skillManager.update();
		if (op != null && op.isTimeout()) {
			op = null;
		}
		// 恢复体力
		long elapseMillis;
		long now = TimeUpdater.getInstance().now();
		if (lastUpdateStrTime > 0L && (elapseMillis = now - lastUpdateStrTime) >= STRENGTH_RECOVERY_TIME_INTERVAL) {
			lastUpdateStrTime = now;
			int val = PlayerUtils.getMaxStrength(this) - getStrength();
			if (val > 0) {
				int n = (int) (elapseMillis / STRENGTH_RECOVERY_TIME_INTERVAL);
				n *= STRENGTH_RECOVERY_VALUE;
				if (n > val) {
					n = val;
				}
				addStrength(n, Cause.AUTO_RECOVERY);
			}
		}
		// 恢复精力
		if (lastUpdateVigourTime > 0L && (elapseMillis = now - lastUpdateVigourTime) >= VIGOUR_RECOVER_TIME_INTERVAL) {
			lastUpdateVigourTime = now;
			int n = (int) (elapseMillis / VIGOUR_RECOVER_TIME_INTERVAL);
			n *= VIGOUR_RECOVER_VALUE;
			int addval = 0;
			if (vigour < VIGOUR_RECOVER_MAX_VALUE) {
				if (vigour + n > VIGOUR_RECOVER_MAX_VALUE) {
					addval =  VIGOUR_RECOVER_MAX_VALUE - vigour;
				} else {
					addval = n;
				}
			}
			addVigour(addval, Cause.AUTO_RECOVERY);
		}
		// 恢复技能点数
		long interval = TimeUnit.MINUTES.toMillis(GameStaticConfig.skillPointsRecoverInterval);
		if (lastUpdateSkillPointsTime > 0L && (elapseMillis = now - lastUpdateSkillPointsTime) >= interval) {
			lastUpdateSkillPointsTime = now;
			int val = GameStaticConfig.maxSkillPoints - getSkillPoints();
			if (val > 0) {
				int n = (int) (elapseMillis / interval);
				n *= GameStaticConfig.skillPointsRecoverVal;
				if (n > val) {
					n = val;
				}
				addSkillPoints(n, Cause.AUTO_RECOVERY);
			}
		}
		
		// 同步累计在线时长（QQ玩吧渠道），每90分钟推送一次
		if (/*NumberUtils.parseInt(getAccount().getChannel()) == AccountChannel.QQ_WANBA.ordinal()
				&& */TimeUpdater.getInstance().now() - lastSyncOnlineTime >= 5400000) {
			lastSyncOnlineTime = TimeUpdater.getInstance().now();
			int onlineTime = (int) ((TimeUpdater.getInstance().now() - lastLoginTime.getTime()) / 1000);
			send(new IntSync(SyncPush.SYNC_ONLINE_TIME, onlineTime));
		}
		
		return true;
	}
	
	public void send(Packet packet) {
		if (session != null) {
			session.send(packet);
		}
	}

	public ConfirmOperation getConfirmOperation() {
		return op;
	}

	public void setConfirmOperation(ConfirmOperation op) {
		this.op = op;
	}

	public int getStrength() {
		return strength + strength2;
	}
	
	/**
	 * 增加免费体力值
	 * @param val
	 * @param cause
	 * @return
	 */
//	@Deprecated
	public boolean addStrength(int val, String cause) {
//		int maxStr;
		if (val <= 0
				|| getStrength() + val <= 0
				/*|| this.strength >= (maxStr = PlayerUtils.getMaxStrength(this))*/) {
			return false;
		}
		int oldVal = getStrength();
		strength += val;
//		if (strength > maxStr) {
//			strength = maxStr;
//		}
		send(new IntSync(SyncPush.SYNC_STRENGTH, getStrength()));
		LOG.info("[ADDSTR]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, getStrength(), cause);
		return true;
	}
	
	public boolean addStrength(int val, LogCause cause) {
		if (val <= 0
				|| getStrength() + val <= 0) {
			return false;
		}
		int oldVal = getStrength();
		strength += val;
		send(new IntSync(SyncPush.SYNC_STRENGTH, getStrength(), cause));
		LOG.info("[ADDSTR]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, getStrength(), cause);
		return true;
	}
	
	/**
	 * 增加购买的体力值
	 * @param val
	 * @param cause
	 * @return
	 */
	public boolean addStrength2(int val, String cause) {
		if (val <= 0 || getStrength() + val <= 0) {
			return false;
		}
		int oldVal = getStrength();
		strength2 += val;
		send(new IntSync(SyncPush.SYNC_STRENGTH, getStrength()));
		LOG.info("[ADDSTR2]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, getStrength(), cause);
		return true;
	}
	
	/**
	 * 扣除体力
	 * @param val 扣除值
	 * @param cause 扣除原因
	 * @return 是否成功
	 */
	public boolean decStrength(int val, String cause) {
		if (val <= 0 || val > getStrength()) {
			return false;
		}
		int oldVal = getStrength();
		strength -= val;
		if (strength < 0) { // 免费体力不足，则扣购买的体力
			val = -strength;
			strength = 0;
			strength2 -= val;
		}
		send(new IntSync(SyncPush.SYNC_STRENGTH, getStrength()));
		LOG.info("[DECSTR]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, getStrength(), cause);
		return true;
	}
	
	/**
	 * 重置体力
	 * @param cause
	 */
	public void resetStrength(String cause) {
		if (pool.getIntValue(PlayerPool.PROPERTY_LAST_RESET_STRENGTH_DAY) == TimeUpdater.getInstance().today()) {
			return;
		}
		poolSet(PlayerPool.PROPERTY_LAST_RESET_STRENGTH_DAY, TimeUpdater.getInstance().today());
		int maxStr = PlayerUtils.getMaxStrength(this);
		if (maxStr == strength) {
			return;
		}
		int oldVal = getStrength();
		strength = maxStr;
		send(new IntSync(SyncPush.SYNC_STRENGTH, getStrength()));
		LOG.info("[RESET STR]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, getStrength(), cause);
	}
	
	/**
	 * 荣誉
	 * @return
	 */
	public int getHonor() {
		return pool.getIntValue(PlayerPool.PROPERTY_HONOR);
	}
	
	public boolean addHonor(int val, String cause) {
		int oldVal = getHonor();
		if (val <= 0 || oldVal + val <= 0) {
			return false;
		}
		int newVal = poolAdd(PlayerPool.PROPERTY_HONOR, val);
		send(new IntSync(SyncPush.SYNC_HONOR, newVal));
		LOG.info("[ADDHONOR]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decHonor(int val, String cause) {
		int oldVal = getHonor();
		if (val <= 0 || val > oldVal) {
			return false;
		}
		int newVal = poolSubtract(PlayerPool.PROPERTY_HONOR, val);
		send(new IntSync(SyncPush.SYNC_HONOR, newVal));
		LOG.info("[DECHONOR]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	/**
	 * 欢乐豆
	 * @return
	 */
	public int getJoyBeans() {
		return pool.getIntValue(PlayerPool.PROPERTY_JOY_BEANS);
	}
	
	public boolean addJoyBeans(int val, String cause) {
		int oldVal = getJoyBeans();
		if (val <= 0 || oldVal + val <= 0) {
			return false;
		}
		int newVal = poolAdd(PlayerPool.PROPERTY_JOY_BEANS, val);
		LOG.info("[ADDJOYBEANS]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decJoyBeans(int val, String cause) {
		int oldVal = getJoyBeans();
		if (val <= 0 || val > oldVal) {
			return false;
		}
		int newVal = poolSubtract(PlayerPool.PROPERTY_JOY_BEANS, val);
		LOG.info("[DECJOYBEANS]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	/**
	 * 护盾数量
	 * @return
	 */
	public int getShield() {
		return pool.getIntValue(PlayerPool.PROPERTY_SHIELD);
	}
	
	public boolean addShield(int val, LogCause cause) {
		int oldVal = getShield();
		if (val <= 0 || oldVal + val <= 0) {
			return false;
		}
		int newVal = poolAdd(PlayerPool.PROPERTY_SHIELD, val);
		if (isOnline()) {
			send(new IntSync(SyncPush.SYNC_SHIELD, newVal, cause));
		}
		LOG.info("[ADDSHIELD]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decShield(int val, LogCause cause) {
		int oldVal = getShield();
		if (val <= 0 || val > oldVal) {
			return false;
		}
		int newVal = poolSubtract(PlayerPool.PROPERTY_SHIELD, val);
		if (isOnline()) {
			send(new IntSync(SyncPush.SYNC_SHIELD, newVal, cause));
		}
		LOG.info("[DECSHIELD]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	/**
	 * 精力
	 * @return
	 */
	public int getVigour() {
		return vigour;//pool.getIntValue(PlayerPool.PROPERTY_VIGOUR);
	}
	
	public boolean addVigour(int val, String cause) {
		int oldVal = getVigour();
//		int maxVal = PlayerUtils.getMaxVigour(this);
		if (val <= 0 || oldVal + val <= 0) {// || oldVal >= maxVal
			return false;
		}
		int newVal = oldVal + val;
//		if (newVal > maxVal) {
//			newVal = maxVal;
//		}
//		poolSet(PlayerPool.PROPERTY_VIGOUR, newVal);
		vigour = newVal;
		send(new IntSync(SyncPush.SYNC_VIGOUR, newVal));
		LOG.info("[ADDVIGOUR]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decVigour(int val, String cause) {
		int oldVal = getVigour();
		if (val <= 0 || val > oldVal) {
			return false;
		}
		int newVal = oldVal - val;
		vigour = newVal;
//		int newVal = poolSubtract(PlayerPool.PROPERTY_VIGOUR, val);
		send(new IntSync(SyncPush.SYNC_VIGOUR, newVal));
		LOG.info("[DECVIGOUR]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public int getBond(){
		return bond;
	}
	
	public boolean addBond(int val, String cause){
		int oldVal = getBond();
		if(val <= 0 || oldVal + val <= 0){
			return false;
		}
		int newVal = oldVal + val;
		bond = newVal;
		send(new IntSync(SyncPush.SYNC_BOND, newVal));
		LOG.info("[ADDBOND]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decBond(int val, String cause){
		int oldVal = getBond();
		if(val <= 0 || val > oldVal){
			return false;
		}
		int newVal = oldVal - val;
		bond = newVal;
		send(new IntSync(SyncPush.SYNC_BOND, newVal));
		LOG.info("[DECBOND]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	/**
	 * 副本星数
	 * @return
	 */
	public int getStageStars() {
		return pool.getIntValue(PlayerPool.PROPERTY_STAGE_STARS);
	}
	
	public boolean addStageStars(int val, String cause) {
		int oldVal = getStageStars();
		if (val <= 0 || oldVal + val <= 0) {
			return false;
		}
		int newVal = oldVal + val;
		poolSet(PlayerPool.PROPERTY_STAGE_STARS, newVal);
		send(new IntSync(SyncPush.SYNC_STAGE_STARS, newVal));
		LOG.info("[ADDSSTARS]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decStageStars(int val, String cause) {
		int oldVal = getStageStars();
		if (val <= 0 || val > oldVal) {
			return false;
		}
		int newVal = poolSubtract(PlayerPool.PROPERTY_STAGE_STARS, val);
		send(new IntSync(SyncPush.SYNC_STAGE_STARS, newVal));
		LOG.info("[DECSSTARS]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	/**
	 * 巅峰币
	 * @return
	 */
	public int getPeakCoin() {
		return pool.getIntValue(PlayerPool.PROPERTY_PEAK_COIN);
	}
	
	public boolean addPeakCoin(int val, String cause) {
		int oldVal = getPeakCoin();
		if (val <= 0 || oldVal + val <= 0) {
			return false;
		}
		int newVal = oldVal + val;
		poolSet(PlayerPool.PROPERTY_PEAK_COIN, newVal);
		send(new IntSync(SyncPush.SYNC_PEAK_COIN, newVal));
		LOG.info("[ADDPEAKCOIN]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decPeakCoin(int val, String cause) {
		int oldVal = getPeakCoin();
		if (val <= 0 || val > oldVal) {
			return false;
		}
		int newVal = poolSubtract(PlayerPool.PROPERTY_PEAK_COIN, val);
		send(new IntSync(SyncPush.SYNC_PEAK_COIN, newVal));
		LOG.info("[DECPEAKCOIN]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	/**
	 * 欢乐转盘积分
	 * @return
	 */
	public int getCircleScore(){
		return circleScore;
	}
	
	public boolean addCircleScore(int val, String cause){
		int oldVal = this.circleScore;
		if(val <= 0 || oldVal + val <= 0){
			return false;
		}
//		int newValue = poolAdd(PlayerPool.PROPERTY_CIRCLE_SCORE, val);
		this.circleScore += val;
		LOG.info("[CIRCLESCORE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.circleScore, cause);
		return true;
	}
	
	public boolean decCircleScore(int val, String cause){
		int oldVal = this.circleScore;
		if(val <= 0 || val > oldVal){
			return false;
		}
//		int newValue = poolSubtract(PlayerPool.PROPERTY_CIRCLE_SCORE, val);
		this.circleScore -= val;
		LOG.info("[CIRCLESCORE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.circleScore, cause);
		return true;
	}
	
	public void resetCircleScore(String cause){
		int oldVal = this.circleScore;
		this.circleScore = 0;
//		getPool().put(PlayerPool.PROPERTY_CIRCLE_SCORE, this.circleScore);
		LOG.info("[CIRCLESCORE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.circleScore, cause);
	}
	
	/**
	 * 免费转盘次数
	 * @return
	 */
	public int getCircleFreeCount(){
		return circleFreeCount;
	}
	
	public boolean addCircleFreeCount(int val, String cause){
		int oldVal = this.circleFreeCount;
		if(val <= 0 || oldVal + val <= 0){
			return false;
		}
		this.circleFreeCount = oldVal + val;
		//poolAdd(PlayerPool.PROPERTY_CIRCLE_FREE_COUNT, val);
		LOG.info("[CIRCLEFREE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.circleFreeCount, cause);
		return true;
	}
	
	public boolean decCircleFreeCount(int val, String cause){
		int oldVal = this.circleFreeCount;
		if(val <= 0 || val > oldVal){
			return false;
		}
		this.circleFreeCount = oldVal - val;
		//poolSubtract(PlayerPool.PROPERTY_CIRCLE_FREE_COUNT, val);
		LOG.info("[CIRCLEFREE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.circleFreeCount, cause);
		return true;
	}
	
	public void resetCircleFreeCount(String cause){
		int oldVal = this.circleFreeCount;
		this.circleFreeCount = 0;
		VipTemplate temp = VipUtils.getTemplate(getVipLvl());
		if(temp != null){
			this.circleFreeCount = temp.getCircleFreeCount();
		}
//		getPool().put(PlayerPool.PROPERTY_CIRCLE_FREE_COUNT, this.circleFreeCount);
		LOG.info("[CIRCLESCORE]ID[{}]NEW[{}]CAUSE[{}]", id, oldVal, this.circleFreeCount, cause);
	}
	
	/**
	 * 技能点数
	 * @return
	 */
	public int getSkillPoints() {
		return pool.getIntValue(PlayerPool.PROPERTY_SKILL_POINTS);
	}
	
	public boolean addSkillPoints(int val, String cause) {
		int oldVal = getSkillPoints();
		if (val <= 0 || oldVal + val <= 0) {
			return false;
		}
		int newVal = oldVal + val;
		poolSet(PlayerPool.PROPERTY_SKILL_POINTS, newVal);
		send(new IntSync(SyncPush.SYNC_SKILL_POINTS, newVal));
		LOG.info("[ADDSKP]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decSkillPoints(int val, String cause) {
		int oldVal = getSkillPoints();
		if (val <= 0 || val > oldVal) {
			return false;
		}
		int newVal = poolSubtract(PlayerPool.PROPERTY_SKILL_POINTS, val);
		send(new IntSync(SyncPush.SYNC_SKILL_POINTS, newVal));
		LOG.info("[DECSKP]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	/**
	 * 王者币
	 * @return
	 */
	public int getKingCoin() {
		return pool.getIntValue(PlayerPool.PROPERTY_KING_COIN);
	}
	
	public boolean addKingCoin(int val, String cause) {
		int oldVal = getKingCoin();
		if (val <= 0 || oldVal + val <= 0) {
			return false;
		}
		int newVal = oldVal + val;
		poolSet(PlayerPool.PROPERTY_KING_COIN, newVal);
		send(new IntSync(SyncPush.SYNC_KING_COIN, newVal));
		LOG.info("[ADDKINGCOIN]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decKingCoin(int val, String cause) {
		int oldVal = getKingCoin();
		if (val <= 0 || val > oldVal) {
			return false;
		}
		int newVal = poolSubtract(PlayerPool.PROPERTY_KING_COIN, val);
		send(new IntSync(SyncPush.SYNC_KING_COIN, newVal));
		LOG.info("[DECKINGCOIN]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}

	
	public int getGuildScore(){
		return pool.getInt(PlayerPool.PROPERTY_GUILD_SCORE, 0);
	}
	
	public boolean addGuildScore(int val, String cause){
		int oldVal = getGuildScore();
		if(val <= 0 || oldVal + val <= 0){
			return false;
		}
		int newVal = poolAdd(PlayerPool.PROPERTY_GUILD_SCORE, val);
		send(new IntSync(SyncPush.SYNC_GUILD_SCORE, newVal));
		LOG.info("[ADDGSCORE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}
	
	public boolean decGuildScore(int val, String cause){
		int oldVal = getGuildScore();
		if(val <= 0 || val > oldVal){
			return false;
		}
		int newVal = poolSubtract(PlayerPool.PROPERTY_GUILD_SCORE, val);
		send(new IntSync(SyncPush.SYNC_GUILD_SCORE, newVal));
		LOG.info("[DECGSCORE]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", id, oldVal, newVal, cause);
		return true;
	}

	public NewPlayerTaskManager getNewPlayerTasks() {
		return newPlayerTask;
	}

	public void setNewPlayerTasks(NewPlayerTaskManager manager) {
		this.newPlayerTask = manager;
		if(manager != null){
			manager.setOwner(this);
		}
	}
	
	public boolean isOnline() {
		return session != null && session.isConnected();
	}
	
	public void poolSet(String key, Object value) {
		pool.put(key, value);
	}
	
	public Object poolRemove(String key) {
		return pool.remove(key);
	}
	
	public byte poolAdd(String key, byte val) {
		byte newVal = (byte) (pool.getByteValue(key) + val);
		poolSet(key, newVal);
		return newVal;
	}
	
	public short poolAdd(String key, short val) {
		short newVal = (short) (pool.getShortValue(key) + val);
		poolSet(key, newVal);
		return newVal;
	}

	public int poolAdd(String key, int val) {
		int newVal = pool.getIntValue(key) + val;
		poolSet(key, newVal);
		return newVal;
	}
	
	public long poolAdd(String key, long val) {
		long newVal = pool.getLongValue(key) + val;
		poolSet(key, newVal);
		return newVal;
	}
	
	public float poolAdd(String key, float val) {
		float newVal = pool.getFloatValue(key) + val;
		poolSet(key, newVal);
		return newVal;
	}
	
	public double poolAdd(String key, double val) {
		double newVal = pool.getDoubleValue(key) + val;
		poolSet(key, newVal);
		return newVal;
	}
	
	public byte poolSubtract(String key, byte val) {
		byte newVal = (byte) (pool.getByteValue(key) - val);
		poolSet(key, newVal);
		return newVal;
	}
	
	public short poolSubtract(String key, short val) {
		short newVal = (short) (pool.getShortValue(key) - val);
		poolSet(key, newVal);
		return newVal;
	}

	public int poolSubtract(String key, int val) {
		int newVal = pool.getIntValue(key) - val;
		poolSet(key, newVal);
		return newVal;
	}
	
	public long poolSubtract(String key, long val) {
		long newVal = pool.getLongValue(key) - val;
		poolSet(key, newVal);
		return newVal;
	}
	
	public float poolSubtract(String key, float val) {
		float newVal = pool.getFloatValue(key) - val;
		poolSet(key, newVal);
		return newVal;
	}
	
	public double poolSubtract(String key, double val) {
		double newVal = pool.getDoubleValue(key) - val;
		poolSet(key, newVal);
		return newVal;
	}
	
//	/**
//	 * 获取成长的战斗属性值（升品、天命）
//	 * @param type
//	 * @return
//	 */
//	@Override
//	public float getEnhancedValue(CombatAttributeType type) {
//		int i = type.ordinal();
//		return attributes != null && i >= 0 && i < attributes.length ? attributes[i] : 0f;
//	}

	//---主属性v2---
//	@Override
//	public float getSTR() {
//		return PlayerUtils.getSTR(this);
//	}
//
//	@Override
//	public float getINT() {
//		return PlayerUtils.getINT(this);
//	}
//
//	@Override
//	public float getAGI() {
//		return PlayerUtils.getAGI(this);
//	}
//
//	@Override
//	public float getSPI() {
//		return PlayerUtils.getSPI(this);
//	}
//
//	@Override
//	public float getSTA() {
//		return PlayerUtils.getSTA(this);
//	}
	//---主属性v2---

	//---战斗属性v2---
	@Override
	public float getAttributeValue(CombatAttributeType type) {
//		return CombatUtils.getAttributeValue(this, type);
		return calc.getValue(type);
	}

	@Override
	public float setAttributeValue(CombatAttributeType type, float value) {
		return 0;
	}
	//---战斗属性v2---
	
	@Override
	public List<DefaultSkillV2> getSkills() {
		DefaultSkillV2 activated = skillManager != null ? skillManager.getActive() : null;
		return activated != null ? Arrays.asList(activated) : Collections.emptyList();
	}
	
	// 升品
	public boolean addQualityLevel(int val, EmployeeQualityUpTemplate template, String cause) {
		int oldLvl = qualityLvl;
		qualityLvl += val;
//		if (attributes == null) {
//			attributes = new float[CombatAttributeType.length()];
//		}
		CombatAttribute[] growthVals = template.getAttributes();
		int mask = 0;
		for (int i = 0; i < growthVals.length; i++) {
			CombatAttribute refer = growthVals[i];
			int offset = refer.getType().ordinal();
//			attributes[offset] += refer.getValue();
			mask |= 1 << offset;
		}
		fireAttributesChanged(mask);
		LOG.info("[PLAYER QUALITY LVLUP]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", getId(), oldLvl, getQualityLvl(), cause);
		return true;
	}

	// 升天命
	public boolean addDestinyLevel(int val, DestinyTemplate template, String cause) {
		int oldLvl = destinyLvl;
		destinyLvl += val;
//		if (attributes == null) {
//			attributes = new float[CombatAttributeType.length()];
//		}
		CombatAttribute[] growthVals = template.getAttributes();
		int mask = 0;
		for (int i = 0; i < growthVals.length; i++) {
			CombatAttribute refer = growthVals[i];
			int offset = refer.getType().ordinal();
//			attributes[offset] += refer.getValue();
			mask |= 1 << offset;
		}
		fireAttributesChanged(mask);
		LOG.info("[PLAYER DESTINY LVLUP]ID[{}]OLD[{}]NEW[{}]CAUSE[{}]", getId(), oldLvl, getDestinyLvl(), cause);
		return true;
	}

	/**
	 * 增加收集过的套装
	 * @param id
	 */
	public void tryAddSuit(int id){
		if(!suitMap.containsKey(id)){
			suitMap.put(id, 1);
		}
	}
	/**
	 * 收集套装数量
	 */
	public int suitCount(){
		return suitMap.size();
	}
	
	@Override
	public int getCombatPower() {
		return combatPower;
	}
	
	@Override
	public void fireAttributesChanged(int mask) {
		if (mask != 0) {
			calc.calc(); // 属性发生变化，强制重新计算一遍
			CombatAttributeType[] types = CombatAttributeType.vals;
			int len = types.length;
			List<CombatAttributeInfo> changes = new ArrayList<>(len);
			for (CombatAttributeType type : types) {
				if ((mask >> type.ordinal() & 1) != 0) { // 只同步发生变化的属性值
					changes.add(new CombatAttributeInfo(type, getAttributeValue(type)));
				}
			}
			send(new MapSync(SyncPush.SYNC_COMBAT_ATTRIBUTES, -1, changes));
			
			int val = CombatUtils.calcCombatPower(this);
			if (val != combatPower) {
				combatPower = val;
				send(new IntSync(SyncPush.SYNC_COMBAT_POWER, val));
				App.getApp().getEventManager().addEvent(GameEvents.EVENT_COMBAT_POWER_CHANGED, this);
			}
		}
	}

	@Override
	public long getFixedAssets() {
		if (fixedAssets < 0) {
			fixedAssets = PlayerUtils.calcFixedAssets(this);
		}
		return fixedAssets;
	}
	
	public long getSkillPointsCD() {
		long interval = TimeUnit.MINUTES.toMillis(GameStaticConfig.skillPointsRecoverInterval);
		long cd = lastUpdateSkillPointsTime + interval - TimeUpdater.getInstance().now();
		return cd > 0 ? cd : 0;
	}
	

	@Override
	public int hashCode() {
		return SerializerUtils.hashCode(this);
	}

	@Override
	public void write(SerializeStream out) {
		SerializerUtils.serialize(this, out);
	}
	
}
